#ifdef WIN32
#ifndef __cplusplus
#error Please compile with a C++ compiler.
#endif
#endif

#if defined(USE_WINDOWS_GDIPLUS)
#include <Windows.h>
#include <GdiPlus.h>

#pragma comment(lib, "gdiplus.lib")
#else
#include <GdiPlusFlat.h>
#endif

#if defined(USE_WINDOWS_GDIPLUS)
using namespace Gdiplus;
using namespace DllExports;
#endif

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "testhelpers.h"

static const char *file = "temp_asset.png";
static WCHAR wFile[] = {'t', 'e', 'm', 'p', '_', 'a', 's', 's', 'e', 't', '.', 'p', 'n', 'g', 0};
GpImage *image;

#define createFile(buffer, expectedStatus) \
{ \
	GpStatus status; \
	FILE *f = fopen (file, "wb+"); \
	assert (f); \
	fwrite ((void *) buffer, sizeof (BYTE), sizeof (buffer), f); \
	fclose (f); \
 \
	status = GdipLoadImageFromFile (wFile, &image); \
	assertEqualInt (status, expectedStatus); \
}

#define createFileSuccess(buffer, format, width, height, flags, propertyCount) \
{ \
	createFile (buffer, Ok); \
	/* FIXME: grayscale image flags are incorrect. */ \
	verifyBitmap (image, pngRawFormat, format, width, height, flags, propertyCount, FALSE); \
	GdipDisposeImage (image); \
}

static void test_valid1bpp()
{
	BYTE grayscale1bpp1x1Interlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x40, 0x69, 0xC9, 0xB2,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x68, 0x00, 0x00, 0x00, 0x82, 0x00, 0x81, 0xA7, 0x01, 0xBA, 0x10,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE grayscale1bpp1x1NotInterlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x37, 0x6E, 0xF9, 0x24,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x98, 0x63, 0x6C, 0xD7,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE grayscale1bpp1x1WithPalette[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x40, 0x69, 0xC9, 0xB2,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x68, 0x00, 0x00, 0x00, 0x82, 0x00, 0x81, 0xA7, 0x01, 0xBA, 0x10,
		/* PLTE */		0x00, 0x00, 0x00, 0x06, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xA5, 0xD9, 0x9F, 0xDD,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE indexed1bpp1x1PaletteFirst[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 0xDB, 0x56, 0xCA,
		/* PLTE */		0x00, 0x00, 0x00, 0x06, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xA5, 0xD9, 0x9F, 0xDD,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x68, 0x00, 0x00, 0x00, 0x82, 0x00, 0x81, 0xA7, 0x01, 0xBA, 0x10,
		/* IEND*/       0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
#if defined(USE_WINDOWS_GDIPLUS)
	BYTE indexed1bpp1x1PaletteLast[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 0xDB, 0x56, 0xCA,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x68, 0x00, 0x00, 0x00, 0x82, 0x00, 0x81, 0xA7, 0x01, 0xBA, 0x10,
		/* PLTE */		0x00, 0x00, 0x00, 0x06, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xA5, 0xD9, 0x9F, 0xDD,
		/* IEND*/       0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
#endif

	createFileSuccess (grayscale1bpp1x1Interlaced, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
	createFileSuccess (grayscale1bpp1x1NotInterlaced, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
	createFileSuccess (grayscale1bpp1x1WithPalette, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
	createFileSuccess (indexed1bpp1x1PaletteFirst, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);

	// FIXME: GDI+ allows indexed images with palettes last.
#if defined(USE_WINDOWS_GDIPLUS)
	createFileSuccess (indexed1bpp1x1PaletteLast, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
}

static void test_valid2bpp ()
{
	BYTE grayscale2bpp1x1Interlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x01, 0x07, 0xC9, 0xB3, 0x62,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x70, 0x00, 0x00, 0x00, 0x42, 0x00, 0x41, 0xF9, 0xFB, 0x3C, 0x49,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE grayscale2bpp6x4NotInterlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xDF, 0x09, 0x3E,
		/* IDAT */      0x00, 0x00, 0x00, 0x14, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x08, 0x0D, 0x60, 0xC8, 0x9A, 0xC0, 0x50, 0x70, 0x81, 0x81, 0x81, 0x01, 0x00, 0x13, 0x83, 0x02, 0xE0, 0x20, 0x93, 0x79, 0xCF,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE grayscale2bpp1x1WithPalette[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x01, 0x07, 0xC9, 0xB3, 0x62,
		/* PLTE */      0x00, 0x00, 0x00, 0x09, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xE6, 0xE6, 0xFA, 0x0D, 0xB2, 0xEB, 0x46,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x70, 0x00, 0x00, 0x00, 0x42, 0x00, 0x41, 0xF9, 0xFB, 0x3C, 0x49,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE indexed2bpp1x1PaletteFirst[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x00, 0x00, 0x01, 0x15, 0x7C, 0x1C, 0x8C,
		/* PLTE */      0x00, 0x00, 0x00, 0x09, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xE6, 0xE6, 0xFA, 0x0D, 0xB2, 0xEB, 0x46,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x70, 0x00, 0x00, 0x00, 0x42, 0x00, 0x41, 0xF9, 0xFB, 0x3C, 0x49,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
#if defined(USE_WINDOWS_GDIPLUS)
	BYTE indexed2bpp6x4PaletteLast[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x02, 0x03, 0x00, 0x00, 0x01, 0xA7, 0x6D, 0x96, 0x46,
		/* IDAT */      0x00, 0x00, 0x00, 0x16, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x70, 0x00, 0x43, 0x1F, 0x86, 0x10, 0x86, 0x23, 0x0C, 0x59, 0x13, 0x18, 0x18, 0x18, 0x00, 0x1B, 0x38, 0x03, 0x1F, 0xE2, 0xF7, 0x9D, 0x3B,
		/* PLTE */      0x00, 0x00, 0x00, 0x09, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xE6, 0xE6, 0xFA, 0x0D, 0xB2, 0xEB, 0x46,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
#endif

	createFileSuccess (grayscale2bpp1x1Interlaced, PixelFormat32bppARGB, 1, 1, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (grayscale2bpp6x4NotInterlaced, PixelFormat32bppARGB, 6, 4, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (grayscale2bpp1x1WithPalette, PixelFormat32bppARGB, 1, 1, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (indexed2bpp1x1PaletteFirst, PixelFormat32bppARGB, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	// FIXME: GDI+ allows indexed images with palettes last.
#if defined(USE_WINDOWS_GDIPLUS)
	createFileSuccess (indexed2bpp6x4PaletteLast, PixelFormat32bppARGB, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
#endif
}

static void test_valid4bpp()
{
	BYTE grayscaleWithAlpha1x1Interlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x01, 0x88, 0x89, 0x46, 0xC2,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x11, 0x75, 0x9A, 0x0F, 0xE8,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE grayscaleWithAlpha6x4NotInterlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x9F, 0xFC, 0x9E,
		/* IDAT */      0x00, 0x00, 0x00, 0x18, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x10, 0x14, 0x14, 0x64, 0x10, 0x71, 0x71, 0x64, 0x90, 0x2F, 0xFF, 0xC8, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x10, 0xFF, 0x02, 0x54, 0xB8, 0xE8, 0x8D, 0xCD,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE grayscaleWithAlpha1x1WithPalette[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x01, 0x88, 0x89, 0x46, 0xC2,
		/* PLTE */      0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x11, 0x75, 0x9A, 0x0F, 0xE8,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE indexed4bpp1x1PaletteFirst[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x03, 0x00, 0x00, 0x01, 0x9A, 0x3C, 0xE9, 0x2C,
		/* PLTE */      0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x11, 0x75, 0x9A, 0x0F, 0xE8,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
#if defined(USE_WINDOWS_GDIPLUS)
	BYTE indexed4bpp6x4PaletteLast[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
		/* IDAT */      0x00, 0x00, 0x00, 0x1B, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x10, 0x00, 0x43, 0xF1, 0x0F, 0x0C, 0x82, 0x02, 0x0C, 0xDF, 0x05, 0x18, 0x44, 0x5C, 0x1C, 0x19, 0x18, 0x18, 0x18, 0x00, 0x22, 0x93, 0x02, 0xF9, 0x27, 0x14, 0x52, 0x58,
		/* PLTE */      0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
#endif

	// GDI+ converts grayscale alpha 4bpp images to 32bpp.
	PixelFormat expectedGrayscalePixelFormat = PixelFormat32bppARGB;
	createFileSuccess (grayscaleWithAlpha1x1Interlaced, expectedGrayscalePixelFormat, 1, 1, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (grayscaleWithAlpha6x4NotInterlaced, expectedGrayscalePixelFormat, 6, 4, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (grayscaleWithAlpha1x1WithPalette, expectedGrayscalePixelFormat, 1, 1, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (indexed4bpp1x1PaletteFirst, PixelFormat4bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
	// FIXME: GDI+ allows indexed images with palettes last.
#if defined(USE_WINDOWS_GDIPLUS)
	createFileSuccess (indexed4bpp6x4PaletteLast, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
}

static void test_valid8bpp ()
{
	BYTE grayscale1x1Interlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x01, 0x4D, 0x79, 0xAB, 0xC3,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0x60, 0x04, 0x00, 0x00, 0x03, 0x00, 0x02, 0xA0, 0x80, 0x44, 0x0F,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE grayscale6x4NotInterlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R',0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x88, 0x6F, 0x11, 0x9F,
		/* IDAT */      0x00, 0x00, 0x00, 0x1D, 'I', 'D', 'A', 'T',0x18, 0x57, 0x63, 0x64, 0x64, 0x00, 0x01, 0x46, 0x46, 0x26, 0x20, 0xF9, 0x8F, 0x89, 0xE1, 0x0F, 0x0B, 0xCB, 0x1F, 0xB0, 0x08, 0x03, 0x03, 0x03, 0x00, 0x24, 0xA0, 0x03, 0x07, 0xA7, 0x85, 0xE0, 0xA2,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D',0xAE, 0x42, 0x60, 0x82
	};
	BYTE grayscale1x1WithPalette[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x01, 0x4D, 0x79, 0xAB, 0xC3,
		/* PLTE */      0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0x60, 0x04, 0x00, 0x00, 0x03, 0x00, 0x02, 0xA0, 0x80, 0x44, 0x0F,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE indexed1x1PaletteFirst[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x03, 0x00, 0x00, 0x01, 0x5F, 0xCC, 0x04, 0x2D,
		/* PLTE */      0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x11, 0x75, 0x9A, 0x0F, 0xE8,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
#if defined(USE_WINDOWS_GDIPLUS)
	BYTE indexed6x4PaletteLast[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x08, 0x03, 0x00, 0x00, 0x01, 0xED, 0xDD, 0x8E, 0xE7,
		/* IDAT */      0x00, 0x00, 0x00, 0x1E, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0x60, 0x84, 0x40, 0xF6, 0xFF, 0x0C, 0x8C, 0x8C, 0x8C, 0x0C, 0xFF, 0xD9, 0x81, 0x6C, 0x66, 0x20, 0x60, 0x64, 0x00, 0x01, 0x06, 0x06, 0x00, 0x2A, 0x5E, 0x02, 0x23, 0xF7, 0x26, 0x7C, 0xAC,
		/* PLTE */      0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
#endif
	BYTE trueColor1x1Interlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x01, 0xE7, 0x70, 0x63, 0x48,
		/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xF8, 0xCF, 0xC0, 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x63, 0x24, 0x55, 0xD3,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE trueColor6x4NotInterlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x08, 0x02, 0x00, 0x00, 0x00, 0x22, 0x66, 0xD9, 0x14,
		/* IDAT */      0x00, 0x00, 0x00, 0x2A, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xFC, 0xCF, 0x80, 0x0E, 0x40, 0x42, 0xCF, 0x9F, 0xFD, 0x82, 0xF2, 0x18, 0x18, 0x24, 0xA5, 0xD8, 0x18, 0x20, 0xAA, 0xDE, 0x35, 0xBD, 0x03, 0x22, 0x20, 0x03, 0xC8, 0x65, 0x04, 0x93, 0x48, 0x80, 0x81, 0x01, 0x00, 0xEE, 0x67, 0x0C, 0xBB, 0x0E, 0x63, 0x55, 0x28,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE trueColor1x1WithPalette[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x01, 0xE7, 0x70, 0x63, 0x48,
		/* PLTE */      0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
		/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xF8, 0xCF, 0xC0, 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x63, 0x24, 0x55, 0xD3,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE trueColorWithAlpha1x1Interlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0x00, 0x00, 0x01, 0x68, 0x12, 0xF4, 0x1F,
		/* IDAT */      0x00, 0x00, 0x00, 0x0D, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xF8, 0xCF, 0xC0, 0xB0, 0x1F, 0x00, 0x04, 0xC0, 0x01, 0xBF, 0xBD, 0x98, 0x5E, 0x91,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE trueColorWithAlpha6x4NotInterlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x08, 0x06, 0x00, 0x00, 0x00, 0xAD, 0x04, 0x4E, 0x43,
		/* IDAT */      0x00, 0x00, 0x00, 0x3E, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xFC, 0xCF, 0xC0, 0xB0, 0x9F, 0x81, 0x81, 0xE1, 0x00, 0x10, 0x5F, 0x03, 0x62, 0x10, 0xD0, 0x02, 0x62, 0x07, 0x06, 0xA0, 0x44, 0xFD, 0xB3, 0x67, 0xBF, 0xFE, 0x23, 0x63, 0x90, 0x18, 0x13, 0x48, 0x89, 0x94, 0x14, 0x1B, 0x23, 0xC7, 0x9C, 0x2F, 0x61, 0x20, 0x0C, 0x62, 0x83, 0xC4, 0x80, 0x04, 0x48, 0x01, 0x3A, 0x60, 0x60, 0x00, 0x00, 0x90, 0x2B, 0x1C, 0x23, 0xE8, 0xDB, 0x69, 0x10,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE trueColorWithAlpha1x1WithPalette[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0x00, 0x00, 0x01, 0x68, 0x12, 0xF4, 0x1F,
		/* PLTE */      0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
		/* IDAT */      0x00, 0x00, 0x00, 0x0D, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xF8, 0xCF, 0xC0, 0xB0, 0x1F, 0x00, 0x04, 0xC0, 0x01, 0xBF, 0xBD, 0x98, 0x5E, 0x91,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};

	// GDI+ converts grayscale 8bpp images to 32bpp.
	PixelFormat expectedGrayscalePixelFormat = PixelFormat32bppARGB;
	createFileSuccess (grayscale1x1Interlaced, expectedGrayscalePixelFormat, 1, 1, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (grayscale6x4NotInterlaced, expectedGrayscalePixelFormat, 6, 4, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (grayscale1x1WithPalette, expectedGrayscalePixelFormat, 1, 1, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (indexed1x1PaletteFirst, PixelFormat8bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
	// FIXME: GDI+ allows indexed images with palettes last.
#if defined(USE_WINDOWS_GDIPLUS)
	createFileSuccess (indexed6x4PaletteLast, PixelFormat8bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
	createFileSuccess (trueColor1x1Interlaced, PixelFormat24bppRGB, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
	createFileSuccess (trueColor6x4NotInterlaced, PixelFormat24bppRGB, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
	createFileSuccess (trueColor1x1WithPalette, PixelFormat24bppRGB, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
	createFileSuccess (trueColorWithAlpha1x1Interlaced, PixelFormat32bppARGB, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (trueColorWithAlpha6x4NotInterlaced, PixelFormat32bppARGB, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (trueColorWithAlpha1x1WithPalette, PixelFormat32bppARGB, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
}

static void test_valid16bpp ()
{
	BYTE grayscale1x1Interlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x1D, 0xE9, 0x77, 0x80,
		/* IDAT */      0x00, 0x00, 0x00, 0x0B, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xA8, 0xFF, 0x0F, 0x00, 0x02, 0x00, 0x01, 0x7F, 0x2F, 0x5A, 0xAA, 0x27,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE grayscale6x4NotInterlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xFF, 0xCD, 0xDC,
		/* IDAT */      0x00, 0x00, 0x00, 0x21, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xFC, 0xFF, 0x9F, 0x01, 0x0E, 0x80, 0x9C, 0x06, 0x28, 0xB3, 0x81, 0x81, 0x85, 0x81, 0xE1, 0x5A, 0x18, 0x94, 0xB7, 0x0A, 0x4A, 0x83, 0x00, 0x03, 0x03, 0x00, 0xF4, 0x31, 0x06, 0xD9, 0x82, 0x8E, 0x6A, 0xA9,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE grayscale1x1WithPalette[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x1D, 0xE9, 0x77, 0x80,
		/* PLTE */      0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
		/* IDAT */      0x00, 0x00, 0x00, 0x0B, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xA8, 0xFF, 0x0F, 0x00, 0x02, 0x00, 0x01, 0x7F, 0x2F, 0x5A, 0xAA, 0x27,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE trueColor1x1Interlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x02, 0x00, 0x00, 0x01, 0xB7, 0xE0, 0xBF, 0x0B,
		/* IDAT */      0x00, 0x00, 0x00, 0x0F, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xF8, 0xFF, 0x9F, 0x81, 0x81, 0x81, 0x01, 0x00, 0x0A, 0xFC, 0x01, 0xFF, 0xC0, 0x18, 0x7E, 0x3E,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE trueColor6x4NotInterlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x10, 0x02, 0x00, 0x00, 0x00, 0x72, 0xF6, 0x05, 0x57,
		/* IDAT */      0x00, 0x00, 0x00, 0x36, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xFC, 0xFF, 0x9F, 0x81, 0x20, 0x80, 0x2A, 0x7A, 0xFE, 0xFC, 0xD9, 0xB3, 0x5F, 0xBF, 0xC0, 0x22, 0x28, 0x40, 0x52, 0x52, 0x4A, 0x8A, 0x8D, 0x8D, 0x01, 0xD9, 0xA4, 0x77, 0xEF, 0x9A, 0x9A, 0xDE, 0x01, 0x01, 0x88, 0x84, 0x88, 0x40, 0x64, 0x19, 0x11, 0x4C, 0x5C, 0x80, 0x81, 0x01, 0x00, 0x87, 0xD4, 0x19, 0x72, 0xFD, 0x0D, 0x0C, 0x10,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE trueColor1x1WithPalette[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x02, 0x00, 0x00, 0x01, 0xB7, 0xE0, 0xBF, 0x0B,
		/* PLTE */      0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
		/* IDAT */      0x00, 0x00, 0x00, 0x0F, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xF8, 0xFF, 0x9F, 0x81, 0x81, 0x81, 0x01, 0x00, 0x0A, 0xFC, 0x01, 0xFF, 0xC0, 0x18, 0x7E, 0x3E,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE trueColorWithAlpha1x1Interlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x06, 0x00, 0x00, 0x01, 0x38, 0x82, 0x28, 0x5C,
		/* IDAT */      0x00, 0x00, 0x00, 0x10, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xF8, 0xFF, 0x9F, 0x01, 0x08, 0xEA, 0xFF, 0x03, 0x00, 0x10, 0xF7, 0x03, 0x7D, 0xF1, 0xE9, 0x90, 0xF9,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE trueColorWithAlpha6x4NotInterlaced[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x10, 0x06, 0x00, 0x00, 0x00, 0xFD, 0x94, 0x92, 0x00,
		/* IDAT */      0x00, 0x00, 0x00, 0x5C, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xFC, 0xFF, 0x9F, 0x01, 0x08, 0xF6, 0x83, 0x49, 0x06, 0x86, 0x03, 0x10, 0x8A, 0xE1, 0x5A, 0x18, 0x94, 0x01, 0x05, 0x5A, 0xAB, 0x20, 0xB4, 0x03, 0x03, 0x54, 0x43, 0xFD, 0xFF, 0xE7, 0xCF, 0x9F, 0x3D, 0xFB, 0xF5, 0xAB, 0x01, 0x2C, 0x8C, 0x0D, 0x48, 0x4A, 0x4A, 0x49, 0xB1, 0xB1, 0x35, 0x30, 0x30, 0x41, 0xF9, 0x0C, 0x52, 0x40, 0xC0, 0xC6, 0xC6, 0xC8, 0xC8, 0xC1, 0x31, 0x67, 0xCE, 0x97, 0x2F, 0x61, 0x61, 0x30, 0x1A, 0x26, 0x0E, 0x55, 0xC6, 0x00, 0x66, 0xFC, 0x07, 0x02, 0x30, 0x8F, 0x20, 0x60, 0x60, 0x00, 0x00, 0x6D, 0xBB, 0x1D, 0xDE, 0xBD, 0x08, 0x32, 0x2C,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE trueColorWithAlpha1x1WithPalette[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x06, 0x00, 0x00, 0x01, 0x38, 0x82, 0x28, 0x5C,
		/* PLTE */      0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
		/* IDAT */      0x00, 0x00, 0x00, 0x10, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xF8, 0xFF, 0x9F, 0x01, 0x08, 0xEA, 0xFF, 0x03, 0x00, 0x10, 0xF7, 0x03, 0x7D, 0xF1, 0xE9, 0x90, 0xF9,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	
	// GDI+ converts grayscale 16bpp images to 32bpp.
	PixelFormat expectedGrayscalePixelFormat = PixelFormat32bppARGB;
	PixelFormat expectedTrueColorPixelFormat = PixelFormat32bppARGB;

	createFileSuccess (grayscale1x1Interlaced, expectedGrayscalePixelFormat, 1, 1, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (grayscale6x4NotInterlaced, expectedGrayscalePixelFormat, 6, 4, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (grayscale1x1WithPalette, expectedGrayscalePixelFormat, 1, 1, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (trueColor1x1Interlaced, expectedTrueColorPixelFormat, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (trueColor6x4NotInterlaced, expectedTrueColorPixelFormat, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (trueColor1x1WithPalette, expectedTrueColorPixelFormat, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (trueColorWithAlpha1x1Interlaced, PixelFormat32bppARGB, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (trueColorWithAlpha6x4NotInterlaced, PixelFormat32bppARGB, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
	createFileSuccess (trueColorWithAlpha1x1WithPalette, PixelFormat32bppARGB, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
}

static void test_valid ()
{
#if defined(USE_WINDOWS_GDIPLUS)
	BYTE longIhdrLength[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0E, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0x00, 0x00, 0x00, 0x00
	};
#endif
#if defined(USE_WINDOWS_GDIPLUS)
	BYTE multipleIhdrs[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x40, 0x69, 0xC9, 0xB2,
		/* PLTE */      0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
		/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
#endif
#if defined(USE_WINDOWS_GDIPLUS)
	BYTE multipleIdats[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x40, 0x69, 0xC9, 0xB2,
		/* PLTE */      0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
		/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x98, 0x63, 0x6C, 0xD7,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
#endif
#if defined(USE_WINDOWS_GDIPLUS)
	BYTE oneEmptyIdat[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IDAT */      0x00, 0x00, 0x00, 0x00, 'I', 'D', 'A', 'T', 0x00, 0x00, 0x00, 0x00,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0x00, 0x00, 0x00, 0x00
	};
#endif
#if defined(USE_WINDOWS_GDIPLUS)
	BYTE multiplePalettes[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
		/* PLTE */      0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
		/* PLTE */      0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
		/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
#endif
	BYTE noIend[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x40, 0x69, 0xC9, 0xB2,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x98, 0x63, 0x6C, 0xD7,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
#if defined(USE_WINDOWS_GDIPLUS)
	BYTE invalidCrc[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0x00, 0x00, 0x00, 0x00
	};
#endif
#if defined(USE_WINDOWS_GDIPLUS)
	BYTE invalidCompression[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0x00, 0x00, 0x00, 0x00
	};
#endif
	BYTE metersPhysicalDimensionsChunk[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
		/* PLTE */      0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
		/* pHYs */      0x00, 0x00, 0x00, 0x09, 'p', 'H', 'Y', 's', 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3, 0x01, 0xC7, 0x6F, 0xA8, 0x64,
		/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE zeroDpiXPhysicalDimensionsChunk[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
		/* PLTE */      0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
		/* pHYs */      0x00, 0x00, 0x00, 0x09, 'p', 'H', 'Y', 's', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xC3, 0x01, 0xC7, 0x6F, 0xA8, 0x64,
		/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE zeroDpiYPhysicalDimensionsChunk[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
		/* PLTE */      0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
		/* pHYs */      0x00, 0x00, 0x00, 0x09, 'p', 'H', 'Y', 's', 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x01, 0xC7, 0x6F, 0xA8, 0x64,
		/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE unknownPhysicalDimensionsChunk[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
		/* PLTE */      0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
		/* pHYs */      0x00, 0x00, 0x00, 0x09, 'p', 'H', 'Y', 's', 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0xC7, 0x6F, 0xA8, 0x64,
		/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE invalidPhysicalDimensionsChunk[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
		/* PLTE */      0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
		/* pHYs */      0x00, 0x00, 0x00, 0x09, 'p', 'H', 'Y', 's', 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x02, 0xC7, 0x6F, 0xA8, 0x64,
		/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE gamaChunkBeforeColors[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
		/* gAMA */      0x00, 0x00, 0x00, 0x04, 'g', 'A', 'M', 'A', 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61, 0x05,
		/* PLTE */      0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
		/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE gamaChunkAfterColors[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
		/* gAMA */      0x00, 0x00, 0x00, 0x04, 'g', 'A', 'M', 'A', 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61, 0x05,
		/* PLTE */      0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
		/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE srgbChunk[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
		/* sRGB */      0x00, 0x00, 0x00, 0x01, 's', 'R', 'G', 'B', 0x00, 0xAE, 0xCE, 0x1C, 0xE9,
		/* PLTE */      0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
		/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
#if defined(USE_WINDOWS_GDIPLUS)
	BYTE unknownChunk[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
		/* UNKNOWN */   0x00, 0x00, 0x00, 0x02, 'U', 'N', 'K', 'N', 0xFE, 0xEF, 0xAE, 0xCE, 0x1C, 0xE9,
		/* PLTE */      0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
		/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
#endif
	BYTE invalidSrgbChunk[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
		/* sRGB */      0x00, 0x00, 0x00, 0x01, 's', 'R', 'G', 'B', 0xFF, 0xAE, 0xCE, 0x1C, 0xE9,
		/* PLTE */      0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
		/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
#if defined(USE_WINDOWS_GDIPLUS)
	BYTE iendWithLength[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x40, 0x69, 0xC9, 0xB2,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x98, 0x63, 0x6C, 0xD7,
		/* IEND */      0x00, 0x00, 0x00, 0x01, 'I', 'E', 'N', 'D', 0x00, 0xAE, 0x42, 0x60, 0x82,
		/* sRGB */      0x00, 0x00, 0x00, 0x01, 's', 'R', 'G', 'B', 0xFF, 0xAE, 0xCE, 0x1C, 0xE9
	};
#endif
	BYTE iendWithTrailingData[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x40, 0x69, 0xC9, 0xB2,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x98, 0x63, 0x6C, 0xD7,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82,
		/* sRGB */      0x00, 0x00, 0x00, 0x01, 's', 'R', 'G', 'B', 0xFF, 0xAE, 0xCE, 0x1C, 0xE9
	};

	// FIXME: GDI+ allows long IHDR lengths.
#if defined(USE_WINDOWS_GDIPLUS)
	createFileSuccess (longIhdrLength, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
	// FIXME: GDI+ allows multiple IHDRs.
#if defined(USE_WINDOWS_GDIPLUS)
	createFileSuccess (multipleIhdrs, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
	//FIXME: GDI+ allows multiple IDATs.
#if defined(USE_WINDOWS_GDIPLUS)
	createFileSuccess (multipleIdats, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
	// FIXME: GDI+ allows empty IDATs.
#if defined(USE_WINDOWS_GDIPLUS)
	createFileSuccess (oneEmptyIdat, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
	// FIXME: GDI+ allows multiple palettes
#if defined(USE_WINDOWS_GDIPLUS)
	createFileSuccess (multiplePalettes, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
	createFileSuccess (noIend, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
	// FIXME: GDI+ does not validate the CRC.
#if defined(USE_WINDOWS_GDIPLUS)
	createFileSuccess (invalidCrc, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
	// FIXME: GDI+ does not validate the compression.
#if defined(USE_WINDOWS_GDIPLUS)
	createFileSuccess (invalidCompression, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
	createFileSuccess (metersPhysicalDimensionsChunk, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsHasRealDPI | ImageFlagsReadOnly, 3);
	createFileSuccess (zeroDpiXPhysicalDimensionsChunk, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
	createFileSuccess (zeroDpiYPhysicalDimensionsChunk, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
	createFileSuccess (unknownPhysicalDimensionsChunk, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
	createFileSuccess (invalidPhysicalDimensionsChunk, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
	createFileSuccess (gamaChunkBeforeColors, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 4);
	createFileSuccess (gamaChunkAfterColors, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 4);
	createFileSuccess (srgbChunk, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 5);
	// FIXME: GDI+ does not validate the CRC.
#if defined(USE_WINDOWS_GDIPLUS)
	createFileSuccess (unknownChunk, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
	createFileSuccess (invalidSrgbChunk, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 5);
	// FIXME: GDI+ does not validate the CRC.
#if defined(USE_WINDOWS_GDIPLUS)
	createFileSuccess (iendWithLength, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
	createFileSuccess (iendWithTrailingData, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
}

static void test_invalidHeader ()
{
	BYTE noP[]       = {0x89};
	BYTE noN[]       = {0x89, 0x50};
	BYTE noG[]       = {0x89, 0x50, 0x4E};
	BYTE noCLRF[]    = {0x89, 0x50, 0x4E, 0x47};
	BYTE shortCLRF[] = {0x89, 0x50, 0x4E, 0x47, 0x0D};
	BYTE noEOF[]     = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A};

	createFile (noP, OutOfMemory);
	createFile (noN, OutOfMemory);
	createFile (noG, OutOfMemory);
	createFile (noCLRF, OutOfMemory);
	createFile (shortCLRF, OutOfMemory);
	createFile (noEOF, OutOfMemory);
}

static void test_invalidHeaderChunk()
{
	BYTE noDataLength[] = {
		/*Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A
	};
	BYTE shortDataLength[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00
	};
	BYTE noDataType[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D
	};
	BYTE shortDataType[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D'
	};
	BYTE noWidth[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R'
	};
	BYTE shortWidth[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00
	};
	BYTE noHeight[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01
	};
	BYTE shortHeight[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
	};
	BYTE noBitDepth[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01
	};
	BYTE noColorType[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01
	};
	BYTE noCompression[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00
	};
	BYTE noFilter[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00
	};
	BYTE noInterlace[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00
	};
	BYTE noCrc[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00
	};
	BYTE noIDAT[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x37, 0x6E, 0xF9, 0x24
	};

	createFile (noDataLength, OutOfMemory);
	createFile (shortDataLength, OutOfMemory);
	createFile (noDataType, OutOfMemory);
	createFile (shortDataType, OutOfMemory);
	createFile (noWidth, OutOfMemory);
	createFile (shortWidth, OutOfMemory);
	createFile (noHeight, OutOfMemory);
	createFile (shortHeight, OutOfMemory);
	createFile (noBitDepth, OutOfMemory);
	createFile (noColorType, OutOfMemory);
	createFile (noCompression, OutOfMemory);
	createFile (noFilter, OutOfMemory);
	createFile (noInterlace, OutOfMemory);
	createFile (noCrc, OutOfMemory);
	createFile (noIDAT, OutOfMemory);
}

static void test_invalidImageData()
{
	BYTE lowerCaseHeaders[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'i', 'h', 'd', 'r', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'i', 'd', 'a', 't', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'i', 'e', 'n', 'd', 0x00, 0x00, 0x00, 0x00
	};
	BYTE shortIhdrLength[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0C, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,  0x00, 0x00,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0x00, 0x00, 0x00, 0x00
	};
	BYTE prematureIend[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x40, 0x69, 0xC9, 0xB2,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x98, 0x63, 0x6C, 0xD7
	};
	BYTE idatFirst[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IHDR */      0x00, 0x00, 0x00, 0x0C, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,  0x00, 0x00,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0x00, 0x00, 0x00, 0x00
	};
	BYTE zeroWidth[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0x00, 0x00, 0x00, 0x00
	};
	BYTE zeroHeight[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0x00, 0x00, 0x00, 0x00
	};
	BYTE invalidInterlace[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0x00, 0x00, 0x00, 0x00
	};

	BYTE invalidBitDepths[] = {0x00, 0x03, 0x05, 0x06, 0x07, 0x09, 0x0F, 0x11};
	for (int i = 0; i < sizeof (invalidBitDepths); i++)
	{
		BYTE invalidBitDepth[] = {
			/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
			/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, invalidBitDepths[i], 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
			/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
			/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0x00, 0x00, 0x00, 0x00
		};
		createFile (invalidBitDepth, OutOfMemory);
	}

	BYTE invalidColorTypes[] = {0x01, 0x05, 0x07};
	for (int i = 0; i < sizeof (invalidColorTypes); i++)
	{
		BYTE invalidColorType[] = {
			/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
			/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, invalidColorTypes[i], 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
			/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
			/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0x00, 0x00, 0x00, 0x00
		};
		createFile (invalidColorType, OutOfMemory);
	}
	BYTE noIdat[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 0xDB, 0x56, 0xCA,
		/* PLTE */		0x00, 0x00, 0x00, 0x06, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xA5, 0xD9, 0x9F, 0xDD,
		/* IEND*/       0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE onlyEmptyIdat[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
		/* IDAT */      0x00, 0x00, 0x00, 0x00, 'I', 'D', 'A', 'T', 0x00, 0x00, 0x00, 0x00,
		/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0x00, 0x00, 0x00, 0x00
	};

	createFile (lowerCaseHeaders, OutOfMemory);
	createFile (shortIhdrLength, OutOfMemory);
	createFile (prematureIend, OutOfMemory);
	createFile (idatFirst, OutOfMemory);
	createFile (zeroWidth, OutOfMemory);
	createFile (zeroHeight, OutOfMemory);
	createFile (invalidInterlace, OutOfMemory);
	createFile (noIdat, OutOfMemory);
	createFile (onlyEmptyIdat, OutOfMemory);
}

static void test_invalidImageFormat()
{
	BYTE indexedNoPalette[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 0xDB, 0x56, 0xCA,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x68, 0x00, 0x00, 0x00, 0x82, 0x00, 0x81, 0xA7, 0x01, 0xBA, 0x10,
		/* IEND*/       0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};
	BYTE indexed16bpp[] = {
		/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
		/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x00, 0x00, 0x00, 0x25, 0xDB, 0x56, 0xCA,
		/* PLTE */		0x00, 0x00, 0x00, 0x06, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xA5, 0xD9, 0x9F, 0xDD,
		/* IDAT */      0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x68, 0x00, 0x00, 0x00, 0x82, 0x00, 0x81, 0xA7, 0x01, 0xBA, 0x10,
		/* IEND*/       0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
	};

	BYTE invalidBitsPerPixel[] = {0x01, 0x02, 0x04};
	for (int i = 0; i < sizeof (invalidBitsPerPixel); i++)
	{
		BYTE trueColorInvalidBpp[] = {
			/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
			/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, invalidBitsPerPixel[i], 0x02, 0x00, 0x00, 0x01, 0xE7, 0x70, 0x63, 0x48,
			/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xF8, 0xCF, 0xC0, 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x63, 0x24, 0x55, 0xD3,
			/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
		};
		BYTE grayscaleWithAlphaInvalidBpp[] = {
			/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
			/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, invalidBitsPerPixel[i], 0x04, 0x00, 0x00, 0x01, 0xE7, 0x70, 0x63, 0x48,
			/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xF8, 0xCF, 0xC0, 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x63, 0x24, 0x55, 0xD3,
			/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
		};
		BYTE trueColorWithAlphaInvalidBpp[] = {
			/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
			/* IHDR */      0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, invalidBitsPerPixel[i], 0x06, 0x00, 0x00, 0x01, 0xE7, 0x70, 0x63, 0x48,
			/* IDAT */      0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xF8, 0xCF, 0xC0, 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x63, 0x24, 0x55, 0xD3,
			/* IEND */      0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
		};

		createFile (trueColorInvalidBpp, OutOfMemory);
		createFile (grayscaleWithAlphaInvalidBpp, OutOfMemory);
		createFile (trueColorWithAlphaInvalidBpp, OutOfMemory);
	}

	createFile (indexedNoPalette, OutOfMemory);
	createFile (indexed16bpp, OutOfMemory);
}

int
main (int argc, char**argv)
{
	STARTUP;

	test_valid1bpp ();
	test_valid2bpp ();
	test_valid4bpp ();
	test_valid8bpp ();
	test_valid16bpp ();
	test_valid ();
	test_invalidHeader ();
	test_invalidHeaderChunk ();
	test_invalidImageData ();
	test_invalidImageFormat ();

	deleteFile (file);

	SHUTDOWN;
	return 0;
}
